package cn.bearspark.user.provider.dao.buffer;

import cn.bearspark.framework.redis.starter.buffer.RedisBuffer;
import cn.bearspark.user.provider.dao.key.UserBufferKeyBuilder;
import cn.bearspark.user.provider.dao.mapper.UserBaseMapper;
import cn.bearspark.user.provider.dao.po.UserIdNamePO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户 id 与 用户名 的缓存器
 * <p>
 * TODO 如果用户修改了用户名，则需要删除这里的缓存和任何带有用户名的缓存
 *
 * @author f
 */
@Component
public class UserIdNameBuffer extends RedisBuffer {

    /**
     * 缓存的过期时长，默认为 3min
     */
    private static final int CACHE_EXPIRE = 3;

    private final UserBaseMapper userBaseMapper;

    private final UserBufferKeyBuilder userBufferKeyBuilder;

    public UserIdNameBuffer(RedisTemplate<String, Object> redisTemplate,
                            UserBaseMapper userBaseMapper,
                            UserBufferKeyBuilder userBufferKeyBuilder) {
        super(redisTemplate);
        this.userBaseMapper = userBaseMapper;
        this.userBufferKeyBuilder = userBufferKeyBuilder;
    }

    /**
     * 将用户名转换成用户 id
     *
     * @param usernameList 待转换的用户名集合
     * @return 用户 id 集合
     */
    public Map<String, Long> map(List<String> usernameList) {
        String key = userBufferKeyBuilder.buildUserIdNameMapKey();

        // 先在缓存中查询用户名对应的用户 id，并收集缺失用户 id 缓存的用户名
        Map<String, Long> map = new HashMap<>();
        List<String> missingUsernameList = new ArrayList<>();
        usernameList.forEach(username -> {
            Object obj = redisTemplate.opsForHash().get(key, username);
            if (obj == null) {
                missingUsernameList.add(username);
            } else {
                map.put(username, super.objToLong(obj));
            }
        });

        // 如果都找到了，则直接返回
        if (missingUsernameList.isEmpty()) {
            return map;
        }

        // 在数据库中查询缺失用户名与用户 id 的映射
        Map<String, Long> missingMap = userBaseMapper.listIdNameByNameList(missingUsernameList)
                .stream().collect(Collectors.toMap(
                        UserIdNamePO::getUsername,
                        UserIdNamePO::getUserId)
                );

        // 缓存查询到的结果
        redisTemplate.opsForHash().putAll(key, missingMap);
        redisTemplate.expire(key, CACHE_EXPIRE, TimeUnit.MINUTES);

        // 将查询到的结果放入结果映射中
        map.putAll(missingMap);

        return map;
    }
}
